﻿using System;
using System.Diagnostics;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Text.RegularExpressions;

namespace Shoy.Wcf.Behaviors
{
    public class LoggerInspector : IClientMessageInspector, IDispatchMessageInspector
    {
        private readonly Action<string> _logAction;

        public LoggerInspector(Action<string> logAction)
        {
            _logAction = logAction;
        }
        private static string ParseOperationName(string action)
        {
            if (string.IsNullOrEmpty(action)) return action;
            var actionName = action;
            var index = action.LastIndexOf('/');
            if (index >= 0)
            {
                actionName = action.Substring(index + 1);
            }
            return actionName;
        }

        private object MarkStartOfOperation(string inspectorType, string operationName, string sessionId)
        {
            //var message = $"开始调用{inspectorType}:{operationName}\t{DateTime.Now:yyyy-MM-dd HH:mm:ss}";
            //Console.WriteLine(message);
            return Stopwatch.StartNew();
        }

        private void MarkEndOfOperation(string inspectorType, string operationName, string sessionId,
            object correlationState)
        {
            var watch = (Stopwatch)correlationState;
            watch.Stop();
            var message = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - 调用{inspectorType}:{operationName}\t耗时：{watch.ElapsedMilliseconds}ms";
            _logAction(message);
        }

        private static string GetMessageBody(string msg)
        {
            var match = Regex.Match(msg, "<s:Body>([\\w\\W]*)</s:Body>");
            return match.Success ? Regex.Replace(match.Groups[1].Value, "([\\t\\r\\n]|(\\s{2,}))", string.Empty) : string.Empty;
        }

        object IDispatchMessageInspector.AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            var msg = GetMessageBody(request.ToString());
            _logAction($"接收：{msg}\t{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
            var context = OperationContext.Current;
            if (context == null) return null;
            var operationName = ParseOperationName(context.IncomingMessageHeaders.Action);
            return MarkStartOfOperation(context.EndpointDispatcher.ContractName, operationName, context.SessionId);
        }

        void IDispatchMessageInspector.BeforeSendReply(ref Message reply, object correlationState)
        {
            var msg = GetMessageBody(reply.ToString());
            _logAction($"发送：{msg}\t{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
            var context = OperationContext.Current;
            if (context == null) return;
            var operationName = ParseOperationName(context.IncomingMessageHeaders.Action);
            MarkEndOfOperation(context.EndpointDispatcher.ContractName, operationName, context.SessionId,
                correlationState);
        }

        object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            Console.WriteLine("客户端发送请求前的SOAP消息：\n{0}", request);
            return null;
        }

        void IClientMessageInspector.AfterReceiveReply(ref Message reply, object correlationState)
        {
            Console.WriteLine("客户端接收到的回复：\n{0}", reply);
        }
    }
}
